package org.epsi.blokus.joueur;

import java.util.ArrayList;
import java.util.Random;
import org.epsi.blokus.Hex;
import org.epsi.blokus.state.JeuState;
import org.epsi.blokus.tools.Log;
import org.epsi.blokus.tools.Point;
import org.newdawn.slick.SlickException;

/**
 * Adversaire en mode Entrainement (offline)
 * @author julien.lafont
 */
public class TrainingOpponent extends Opponent {

    protected Random random;

    public static enum STRATEGY { RANDOM, STICK_TOGETHER, STICK_SOLO }; // Aléatoire, Collé-Serré, Collé-serré sur soi même

    // Stratégie mise en place
    private STRATEGY strategy = STRATEGY.RANDOM;

    
    public TrainingOpponent(TTypePiece couleur) {
        super(couleur);
        this.random = new Random(System.currentTimeMillis());
    }

    /**
     * Changer la stratégie utilisée par l'IA
     * @param strategy
     */
    public void setStrategy(STRATEGY strategy) {
        this.strategy = strategy;
    }

    /**
     * L'IA est toujours prête
     * @return
     */
    public boolean isReady()
    {
        return true;
    }

    /**
     * L'IA Joue un coup en fontion de la stratégie choisie
     */
    public void jouerCoupAleatoire()
    {
        try {
            Log.out("LocalGame : Jouer coup");

            // Simule le fait de réfléchir !
            Thread.sleep(MIN_WAIT + random.nextInt(RANDOM_WAIT));

            TTypePiece couleurAdverse = Hex.getInstance().getPlayer().getCouleur();
            Point caseJouee = null;

            switch(strategy)
            {

                case STICK_SOLO:
                case STICK_TOGETHER:
                    
                    // Liste les cases vides classés de manière pondérée, en fonction du nombre de voisins ennemis
                    ArrayList<Point> listeCasesVidesPonderes[] = new ArrayList[6]; // 6 car une case a 6 voisins
                    for (int i=0; i<6; i++) listeCasesVidesPonderes[i] = new ArrayList<Point>();

                    // Classe les cases vides en fonction de leur pondération
                    int ptMax=0;
                    for (int i = 0; i < NB_CASES; i++) for (int j = 0; j < NB_CASES; j++)  if (this.board.isFree(i, j)) {
                        Integer pt = this.board.countNeighbor(i, j, (strategy == STRATEGY.STICK_TOGETHER) ? couleurAdverse : couleur);
                        listeCasesVidesPonderes[pt].add(new Point(i,j));
                        if (pt>ptMax) ptMax=pt;
                    }

                    // Choisit une des cases parmis celles ayant la plus forte pondération
                    caseJouee = listeCasesVidesPonderes[ptMax].get(random.nextInt(listeCasesVidesPonderes[ptMax].size()));
                    
                break;

                default:
                case RANDOM:

                    // Liste toutes les cases vides
                    ArrayList<Point> listeCasesVides = new ArrayList<Point>();
                    for (int i = 0; i < NB_CASES; i++) for (int j = 0; j < NB_CASES; j++)  if (this.board.isFree(i, j)) listeCasesVides.add(new Point(i,j));

                    // Choisit une case vide aléatoirement
                    caseJouee = listeCasesVides.get(random.nextInt(listeCasesVides.size()));
                    
                break;
            }

            // Joue la case sélectionnée
            this.board.addPiece(caseJouee.getX(), caseJouee.getY(), this.getCouleur());
            
        } catch (InterruptedException ex) {
           Log.out("ERREUR : TrainingOppopent > Impossible d'ajouter une pièce");
        } catch (SlickException ex) {
            Log.out("ERREUR : TrainingOppopent > Impossible d'ajouter une pièce");
        }
        finally {
            
            // Il a joué on relache le semaphore pour continuer la partie
            semTourDeJeu.release();
        }
    }


    @Override
    public void setChatState(JeuState state) {
       // Nothing en local
    }

    

}
